import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { Box3,Vector3,Matrix4,Group, ObjectLoader,AxesHelper } from "three";
import ModelDB from './model-db';

// 创建数据库实例
const myDB = new ModelDB();

// 配置常量
const MIN_BATCH_TIME = 500; // 每批模型最小加载时间(ms)
const BASE_CONCURRENCY = 2; // 基础并发数
const MAX_CONCURRENCY = 6; // 最大并发数

async function loadModelsWithProgress(models, partNames, onProgress) {
  const fbxLoader = new FBXLoader();
  const gltfLoader = new GLTFLoader();
  const objectLoader = new ObjectLoader();

  // 动态计算并发数
  const dynamicConcurrency = Math.min(
    MAX_CONCURRENCY,
    BASE_CONCURRENCY + Math.floor(partNames.length / 20)
  );

  console.log(`使用并发数: ${dynamicConcurrency}, 总模型数: ${partNames.length}`);

  let loadedCount = 0;
  const totalCount = partNames.length;

  // 初始化进度
  onProgress({
    progress: 0,
    loaded: 0,
    total: totalCount,
    msg: '准备加载模型...'
  });

  // 分批加载模型
  for (let i = 0; i < partNames.length; i += dynamicConcurrency) {
    const batchStartTime = performance.now();
    const chunk = partNames.slice(i, i + dynamicConcurrency);
    
    // 加载当前批次
    await Promise.all(chunk.map(name => loadSingleModel(name)));
    
    // 更新加载计数
    loadedCount += chunk.length;
    
    // 计算批次耗时
    const batchTime = performance.now() - batchStartTime;
    
    // 如果批次加载太快，延迟到最小时间
    if (batchTime < MIN_BATCH_TIME) {
      await new Promise(resolve => 
        setTimeout(resolve, MIN_BATCH_TIME - batchTime)
      );
    }
    
    // 更新进度
    const progress = Math.round((loadedCount / totalCount) * 100);
    onProgress({
      progress: Math.min(99, progress), // 最大99%，完成时再显示100%
      loaded: loadedCount,
      total: totalCount,
      msg: `加载中: ${Math.min(99, progress)}%`
    });
  }

 

  async function loadSingleModel(name) {
    let loader = null;
    let basicUrl = '';
    
    if (name.indexOf('.fbx') > -1) {
      basicUrl = name;
      loader = fbxLoader;
    } else {
      basicUrl = `/public/models/${name}.glb`;
      loader = gltfLoader;
    }

    try {
      const model = await new Promise((resolve, reject) => {
        // 先尝试从数据库加载
        myDB.get(name).then(data => {
          if (data) {
            // 数据库中有缓存
            const model = objectLoader.parse(data.model);
            resolve(model);
          } else {
            // 从网络加载
            loader.load(
              basicUrl,
              model => {
                let resultModel = model.scene ? model.scene : model;
                resultModel.userData.isPart = true;
                
                // 缓存到数据库
                myDB.add({
                  name,
                  model: resultModel.toJSON()
                }).catch(e => console.error('缓存失败:', e));
                
                resolve(resultModel);
              },
              undefined, // 不监听加载进度
              error => reject(error)
            );
          }
        }).catch(reject);
      });
      
      models[name] = model;
      return model;
    } catch (error) {
      console.error(`加载模型失败: ${name}`, error);
      return null;
    }
  }
}

/**
 * 处理结构树查询有哪些零件要加载
 */
function handleTree(obj, partNames = []) {
  if (obj.children && obj.children.length) {
    obj.children.forEach(item => {
      if (item.type === 'CATPart') partNames.push(item.name)
      handleTree(item, partNames)
    })
  }
  return partNames
}

// 导出优化后的初始化函数
export async function loadingModels(models, treeJson) {
  const progressUI = createProgressUI();

  try {
    let parts = {}
    let names = Array.from(new Set(handleTree(treeJson)))


    await loadModelsWithProgress(
      parts,
      names,
      progressUI.update,
    );

    // 递归组装模型
    assembleModel(models, treeJson, parts);

    // 整个模型居中 需要加个group辅助
    let centerModel = models.children.find(item => item.userData.isPartBox)
    const box = new Box3().setFromObject(centerModel);
    const center = box.getCenter(new Vector3());
    centerModel.position.sub(center);
    
    // 模型局部坐标系显示
    // const axesHelper = new AxesHelper(1000); // 2个单位长度
    // models.add(axesHelper);

    progressUI.remove()
  } catch (error) {
    console.error('模型加载失败:', error);
    progressUI.update({
      progress: 100,
      msg: '加载失败'
    });
    throw error;
  }
}


// 进度条样式
function createProgressUI() {
  // 创建主容器
  const container = document.createElement('div');
  Object.assign(container.style, {
    position: 'fixed',
    top: '0',
    left: '0',
    width: '100%',
    height: '100%',
    background: 'rgba(0,0,0,0.9)', // 更深的背景提高对比度
    display: 'flex',
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    zIndex: '10000',
    color: 'white',
    fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif', // 更现代的字体栈
    transition: 'opacity 0.3s ease-out', // 更平滑的过渡
    pointerEvents: 'none' // 防止点击干扰
  });

  // 创建加载动画
  const spinner = document.createElement('div');
  Object.assign(spinner.style, {
    border: '4px solid rgba(255, 255, 255, 0.15)',
    borderRadius: '50%',
    borderTop: '4px solid #4CAF50', // 使用主题色
    width: '48px',
    height: '48px', // 稍大一些
    animation: 'spin 1s ease-in-out infinite', // 更平滑的动画
    marginBottom: '24px',
    willChange: 'transform' // 优化动画性能
  });

  // 创建进度条容器
  const progressBar = document.createElement('div');
  Object.assign(progressBar.style, {
    width: 'min(80%, 400px)', // 响应式宽度
    height: '8px',
    background: 'rgba(255,255,255,0.1)',
    borderRadius: '4px',
    overflow: 'hidden',
    margin: '16px 0',
    boxShadow: '0 1px 3px rgba(0,0,0,0.2)' // 添加深度感
  });

  // 创建进度条填充部分
  const progressFill = document.createElement('div');
  Object.assign(progressFill.style, {
    height: '100%',
    width: '0%',
    background: 'linear-gradient(90deg, #4CAF50, #8BC34A)',
    transition: 'width 0.2s cubic-bezier(0.4, 0, 0.2, 1)', // 更自然的缓动
    borderRadius: '4px'
  });

  // 创建进度百分比文本
  const progressText = document.createElement('div');
  Object.assign(progressText.style, {
    fontSize: '20px',
    fontWeight: '600', // 半粗体更易读
    margin: '8px 0 4px',
    letterSpacing: '0.5px'
  });


  // 添加CSS动画
  const style = document.createElement('style');
  style.textContent = `
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
  `;

  // 组装所有元素
  progressBar.appendChild(progressFill);
  container.append(style, spinner, progressText, progressBar);
  document.body.appendChild(container);

  return {
    update: ({ progress, msg, loaded, total }) => {
      const roundedProgress = Math.round(progress);
      progressFill.style.width = `${parseInt(roundedProgress)}%`;
      progressText.textContent = msg ? msg : `模型：${loaded}/${total} 进度：${roundedProgress}%`;
    },
    remove: () => {
      progressFill.style.background = '#4CAF50';
      progressText.textContent = '加载完成!';
      spinner.style.borderTopColor = '#ffffff'; // 完成时改变颜色
      setTimeout(() => {
        container.style.opacity = '0';
        container.style.pointerEvents = 'none';
        if (container.parentNode) {
          container.remove();
        }
      }, 500);
    },
    getElement: () => container // 添加获取元素的方法
  };
}

// 递归组装模型
function assembleModel(parent, node, parts, inheritedMatrix = null) {
  // console.group(`Processing node: ${node.name} (${node.type})`);

  // 1. 解析当前节点的变换矩阵
  const nodeMatrix = new Matrix4();
  if (node.position_arr) {
      const arr = node.position_arr;
      // 注意：CATIA使用行主序，Three.js使用列主序
      nodeMatrix.set(
          arr[0], arr[1], arr[2], arr[9],
          arr[3], arr[4], arr[5], arr[10],
          arr[6], arr[7], arr[8], arr[11],
          0, 0, 0, 1
      );
      // console.log('Local matrix:', nodeMatrix);
  }

  // 2. 计算世界矩阵
  const worldMatrix = new Matrix4();
  if (inheritedMatrix) {
      worldMatrix.multiplyMatrices(inheritedMatrix, nodeMatrix);
  } else {
      worldMatrix.copy(nodeMatrix);
  }
  // console.log('World matrix:', worldMatrix);

  if (node.type === 'CATPart' && parts[node.name]) {
      // 3. 处理零件节点
      const model = parts[node.name].clone(true);

      // 高亮使用物料也要复制一份 不然更改的是所有的物料
      // 替换整个模型的材质
      let materialUuid = []
      let materialObj = {}
      model.traverse((child) => {
        if (child.isMesh) {
          if(materialUuid.includes(child.uuid)) {
            child.material = materialObj[child.uuid]
          } else {
            materialObj[child.uuid] = child.material.clone();
            child.material = child.material.clone();



            // child.castShadow = true;
            // child.receiveShadow = true;
            
            // 强制覆盖材质参数（可选）
            if (child.material) {
              // child.material.color.setHex(0xaaaaaa);
              child.material.metalness = 1;  // 金属度
              child.material.roughness = 0.8; // 粗糙度
              child.material.clearcoat = 0.5;
              child.material.clearcoatRoughness= 0.1   // 涂层粗糙度
              child.material.ior= 2.0,                 // 折射率
              child.material.specularIntensity= 1.2,    // 镜面强度
              child.material.envMapIntensity = 2.5; // 环境反射强度
            }
          }
        }
      });

      // 重置原有变换（重要！）
      model.position.set(0, 0, 0);
      model.quaternion.set(0, 0, 0, 1);
      model.scale.set(1000, 1000, 1000);

      // 旋转零件 由于v5是z轴朝上，threejs 是y轴朝上，所以需要旋转90度
      // model.rotation.x = Math.PI / 2;
      model.quaternion.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);

      // 应用完整的世界变换
      model.applyMatrix4(nodeMatrix);

      // console.log('Model final position:', model.position);
      // console.log('Model final rotation:', model.rotation);
      parent.add(model);
      node.uuid = model.uuid
  }
  else if (node.type === 'CATProduct' && node.children) {
      // 4. 处理装配体节点
      const assemblyGroup = new Group();
      node.uuid = assemblyGroup.uuid
      assemblyGroup.userData.isPartBox = true

      // 应用装配体级别的变换
      assemblyGroup.applyMatrix4(worldMatrix);

      // 旋转二级装配体 由于v5是z轴朝上，threejs 是y轴朝上，所以需要旋转90度
      assemblyGroup.quaternion.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);

      // 递归处理子节点
      node.children.forEach(child => {
          assembleModel(assemblyGroup, child, parts, worldMatrix);
      });

      parent.add(assemblyGroup);
      // console.log('Assembly group position:', assemblyGroup.position);
  }
  // const pathOrName = node.path || node.name
  // console.log(`组装节点: ${pathOrName}`, {
  //     position: new Vector3().setFromMatrixPosition(worldMatrix),
  //     matrix: worldMatrix
  // });
  // console.groupEnd();
}